﻿/******************************************************************************
 *
 * @copyright:          Copyright 2011 UniSky Ltd.
 * @file:
 * @author:              kenping.liu
 * @creation:
 * @description:
 *
 * @modifications
 * date         user                description
 *
 *
 * @more-details
 *
 *****************************************************************************/

#include "u/u_logger.h"
#include "u/u_io.h"
#include "u/u_util.h"
#include "syslog.h"
U_NAMESPACE_BEGIN(u)

const char LEVEL_NAMES[8][6] = {"", "trace", "debug", "info ", "warn ", "error", "fatal", ""};
Log _g_kp_log;
u::sys::Lock     _uni_lock;

///////////////////////////////////////////////////////////////////////////////////
Log::Log() {
	// open syslog
	memset(_module, 0, sizeof(_module));
	snprintf(_module, sizeof(_module), "ulog_%s", u::Util::module_name());
	openlog(_module, LOG_CONS | LOG_ODELAY | LOG_PID, 0);
}

Log::~Log() {
	//close syslog
	closelog();
}

void Log::trace(const TCHAR* fmt, ...)
{
    va_list params;
    va_start(params, fmt);
    _g_kp_log.log(L_TRACE, fmt, params);
    va_end(params);
}

void Log::debug(const TCHAR* fmt, ...)
{
    va_list params;
    va_start(params, fmt);
    _g_kp_log.log(L_DEBUG, fmt, params);
    va_end(params);
}

void Log::info(const TCHAR* fmt, ...)
{
    va_list params;
    va_start(params, fmt);
    _g_kp_log.log(L_INFO, fmt, params);
    va_end(params);
}

void Log::warn(const TCHAR* fmt, ...)
{
    va_list params;
    va_start(params, fmt);
    _g_kp_log.log(L_WARN, fmt, params);
    va_end(params);
}

void Log::error(const TCHAR* fmt, ...)
{
    va_list params;
    va_start(params, fmt);
    _g_kp_log.log(L_ERROR, fmt, params);
    va_end(params);
}

void Log::fatal(const TCHAR* fmt, ...)
{
    va_list params;
    va_start(params, fmt);
    _g_kp_log.log(L_FATAL, fmt, params);
    va_end(params);
}

void Log::write(const char* file, const char* fmt, ...)
{
    u::sys::AutoLock lck(&_uni_lock);
    static u::AutoHeap msg(10240);
    static u::AutoHeap body(10240);
    msg.zero();
    body.zero();

    va_list params;
    va_start(params, fmt);
#if defined(WINDOWS)
    u_vsprintf(body.head(), 10240, fmt, params);
#else
    u_vsprintf(body.head(), fmt, params);
#endif
    va_end(params);

#if defined(WINDOWS)
    SYSTEMTIME systm = {0};
    ::GetLocalTime(&systm);
    u_sprintf(msg.head(), 10240, _T("[%02u:%02u:%02u] %s\n"),
            systm.wHour, systm.wMinute, systm.wSecond, body.head());
#else
    struct timeval tv = { 0 };
    gettimeofday(&tv, NULL);
    time_t _time = tv.tv_sec;
    struct tm  occurs = {0};
    localtime_r(&_time, &occurs);
#ifdef __x86_64__
    u_sprintf(msg.head(), _T("[%04d/%02d/%02d %02u:%02u:%02u.%03ld] %s\n"),
            1900+occurs.tm_year, (1+occurs.tm_mon), occurs.tm_mday,
            occurs.tm_hour, occurs.tm_min, occurs.tm_sec, (int64_t)(tv.tv_usec)/1000, body.head());
#else
    u_sprintf(msg.head(), _T("[%04d/%02d/%02d %02u:%02u:%02u.%03lld] %s\n"),
            1900+occurs.tm_year, (1+occurs.tm_mon), occurs.tm_mday,
            occurs.tm_hour, occurs.tm_min, occurs.tm_sec, (int64_t)(tv.tv_usec)/1000, body.head());
#endif
#endif
    u::io::File::append(file, msg.head(), strlen(msg.head()));
    syslog(LOG_INFO, "%s", msg.head());

	printf("%s", msg.head());
}

void Log::log(UINT _Level, const TCHAR* _Fmt,  va_list _Args)
{
//    u::sys::AutoLock lck(&_lock);

    ZeroMemory(&_msg, 40960);
    ZeroMemory(&_dbg_msg, 51200);
    
    u_vsprintf(_msg, _Fmt, _Args);
#if defined(WINDOWS)
    SYSTEMTIME systm = {0};
    ::GetLocalTime(&systm);
    u_sprintf(_dbg_msg, _T("[%02u:%02u:%02u][%s] %s\n"),
            systm.wHour, systm.wMinute, systm.wSecond,
            LEVEL_NAMES[_Level], _msg);
    OutputDebugString(_dbg_msg);
#else
    struct timeval tv = { 0 };
    gettimeofday(&tv, NULL);
    time_t _time = tv.tv_sec;
    struct tm  occurs = {0};
    localtime_r(&_time, &occurs);
    u_sprintf(_dbg_msg, _T("[%04d/%02d/%02d %02u:%02u:%02u.%03ld][%s] %s\n"),
    			(1900+occurs.tm_year), (1+occurs.tm_mon), occurs.tm_mday,
            occurs.tm_hour, occurs.tm_min, occurs.tm_sec, tv.tv_usec/1000,
            LEVEL_NAMES[_Level], _msg);
    printf("%s", _dbg_msg);
#endif
}

U_NAMESPACE_END(u)
